package com.example.main.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;

import com.example.main.R;
import com.zjun.widget.RuleView;

public class MyRuleView extends View {

    private static final String TAG = "MyRuleView";

    /**
     * 滑动阈值
     */
    private int TOUCH_SLOP = 0;
    /**
     * 惯性滑动最小、最大速度
     */
    private int MIN_FLING_VELOCITY = 0;
    private int MAX_FLING_VELOCITY = 0;

    /**
     * 背景色
     */
    private int bgColor;
    /**
     * 刻度颜色
     */
    private int gradationColor;
    /**
     * 短刻度线宽度
     */
    private float shortLineWidth;
    /**
     * 长刻度线宽度
     * 默认 = 2 * shortLineWidth
     */
    private float longLineWidth;
    /**
     * 短刻度长度
     */
    private float shortGradationLen;
    /**
     * 长刻度长度
     * 默认为短刻度的2倍
     */
    private float longGradationLen;
    /**
     * 刻度字体颜色
     */
    private int textColor;
    /**
     * 刻度字体大小
     */
    private float textSize;
    /**
     * 中间指针线颜色
     */
    private int indicatorLineColor;
    /**
     * 中间指针线宽度
     */
    private float indicatorLineWidth;
    /**
     * 中间指针线长度
     */
    private float indicatorLineLen;
    /**
     * 最小值
     */
    private float minValue;
    /**
     * 最大值
     */
    private float maxValue;
    /**
     * 当前值
     */
    private float currentValue;
    /**
     * 刻度最小单位
     */
    private float gradationUnit;
    /**
     * 需要绘制的数值
     */
    private int numberPerCount;
    /**
     * 刻度间距离
     */
    private float gradationGap;
    /**
     * 刻度与文字的间距
     */
    private float gradationNumberGap;

    /**
     * 最小数值，放大10倍：minValue * 10
     */
    private int mMinNumber;
    /**
     * 最大数值，放大10倍：maxValue * 10
     */
    private int mMaxNumber;
    /**
     * 当前数值
     */
    private int mCurrentNumber;
    /**
     * 最大数值与最小数值间的距离：(mMaxNumber - mMinNumber) / mNumberUnit * gradationGap
     */
    private float mNumberRangeDistance;
    /**
     * 刻度数值最小单位：gradationUnit * 10
     */
    private int mNumberUnit;
    /**
     * 当前数值与最小值的距离：(mCurrentNumber - minValue) / mNumberUnit * gradationGap
     */
    private float mCurrentDistance;
    /**
     * 控件宽度所占有的数值范围：mWidth / gradationGap * mNumberUnit
     */
    private int mWidthRangeNumber;

    /**
     * 普通画笔
     */
    private Paint mPaint;
    /**
     * 文字画笔
     */
    private TextPaint mTextPaint;
    /**
     * 速度跟踪器
     */
    private VelocityTracker mVelocityTracker;
    /**
     * 尺寸
     */
    private int mWidth, mHeight;

    private int mDownX;
    private int mLastX, mLastY;
    private boolean isMoved;

    private RuleView.OnValueChangedListener mValueChangedListener;

    /**
     * 当前值变化监听器
     */
    public interface OnValueChangedListener {
        void onValueChanged(float value);
    }


    public MyRuleView(Context context) {
        this(context, null);
    }

    public MyRuleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyRuleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);

        // 初始化final常量，必须在构造中赋初值
        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
        TOUCH_SLOP = viewConfiguration.getScaledTouchSlop();
        MIN_FLING_VELOCITY = viewConfiguration.getScaledMinimumFlingVelocity();
        MAX_FLING_VELOCITY = viewConfiguration.getScaledMaximumFlingVelocity();

        convertValue2Number();
        init(context);
    }

    private void init(Context context) {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStrokeWidth(shortLineWidth);
        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setTextSize(textSize);
        mTextPaint.setColor(textColor);
    }

    private void convertValue2Number() {
        mMinNumber = (int) (minValue * 10);
        mMaxNumber = (int) (maxValue * 10);
        mCurrentNumber = (int) (currentValue * 10);
        mNumberUnit = (int) (gradationUnit * 10);
        mCurrentDistance = 0;
        mNumberRangeDistance = (mMaxNumber - mMinNumber) / mNumberUnit * gradationGap;
        if (mWidth != 0) {
            mWidthRangeNumber = (int) (mWidth / gradationGap * mNumberUnit);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mWidth = calculateSize(true, widthMeasureSpec);
        mHeight = calculateSize(false, heightMeasureSpec);

        if (mWidth != 0) {
            mWidthRangeNumber = (int) (mWidth / gradationGap * mNumberUnit);
        }

        setMeasuredDimension(mWidth, mHeight);
    }

    private int calculateSize(boolean isWidth, int spec) {
        final int mode = MeasureSpec.getMode(spec);
        final int size = MeasureSpec.getSize(spec);
        int realSize = size;

        switch (mode) {
            case MeasureSpec.EXACTLY:
                break;
            case MeasureSpec.AT_MOST:
                if (!isWidth) {
                    int defaultContentSize = dp2px(80);
                    realSize = Math.min(realSize, defaultContentSize);
                }
                break;
            case MeasureSpec.UNSPECIFIED:
            default:
        }

        return realSize;
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RuleView);
        bgColor = ta.getColor(R.styleable.MyRuleView_mcl_bgColor, Color.parseColor("#00ff00"));
        gradationColor = ta.getColor(R.styleable.MyRuleView_mcl_gradationColor, Color.BLACK);
        shortLineWidth = ta.getDimension(R.styleable.MyRuleView_mcl_shortLineWidth, dp2px(1));
        shortGradationLen = ta.getDimension(R.styleable.MyRuleView_mcl_shortGradationLen, dp2px(16));
        longGradationLen = ta.getDimension(R.styleable.MyRuleView_mcl_longGradationLen, shortGradationLen * 2);
        longLineWidth = ta.getDimension(R.styleable.MyRuleView_mcl_longLineWidth, shortLineWidth * 2);
        textColor = ta.getColor(R.styleable.MyRuleView_mcl_textColor, Color.BLACK);
        textSize = ta.getDimension(R.styleable.MyRuleView_mcl_textSize, sp2px(14));
        indicatorLineColor = ta.getColor(R.styleable.MyRuleView_mcl_indicatorLineColor, Color.parseColor("#48b975"));
        indicatorLineWidth = ta.getDimension(R.styleable.MyRuleView_mcl_indicatorLineWidth, dp2px(3f));
        indicatorLineLen = ta.getDimension(R.styleable.MyRuleView_mcl_indicatorLineLen, dp2px(35f));
        minValue = ta.getFloat(R.styleable.MyRuleView_mcl_minValue, 0f);
        maxValue = ta.getFloat(R.styleable.MyRuleView_mcl_maxValue, 100f);
        currentValue = ta.getFloat(R.styleable.MyRuleView_mcl_currentValue, 50f);
        gradationUnit = ta.getFloat(R.styleable.MyRuleView_mcl_gradationUnit, .1f);
        numberPerCount = ta.getInt(R.styleable.MyRuleView_mcl_numberPerCount, 10);
        gradationGap = ta.getDimension(R.styleable.MyRuleView_mcl_gradationGap, dp2px(10));
        gradationNumberGap = ta.getDimension(R.styleable.MyRuleView_mcl_gradationNumberGap, dp2px(8));
        ta.recycle();
    }

    private int dp2px(float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    private int sp2px(float sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 1 绘制背景色
        canvas.drawColor(bgColor);
        // 2 绘制刻度、数字
        drawGradation(canvas);
    }

    /**
     * 绘制刻度
     */
    private void drawGradation(Canvas canvas) {
        // 1 顶部基准线
        mPaint.setColor(gradationColor);
        mPaint.setStrokeWidth(shortLineWidth);
        canvas.drawLine(0, shortLineWidth * .5f, mWidth, 0, mPaint);

        int startNum = (int) mCurrentDistance / (int) gradationGap * mNumberUnit + mMinNumber;
        int rightMaxNum = startNum + mWidthRangeNumber;
        if (rightMaxNum > mMaxNumber) {
            rightMaxNum = mMaxNumber;
        }

        float distance = 0;
        final int perUnitCount = mNumberUnit * numberPerCount;

        while (startNum <= rightMaxNum) {
            if (startNum % perUnitCount == 0) {//长刻度
                mPaint.setStrokeWidth(longLineWidth);
                canvas.drawLine(distance, 0, distance, longGradationLen, mPaint);
                // 数值
                float fNum = startNum / 10f;
                String text = Float.toString(fNum);
                if (text.endsWith(".0")) {
                    text = text.substring(0, text.length() - 2);
                }
                final float textWidth = mTextPaint.measureText(text);
                canvas.drawText(text, distance - textWidth * .5f, longGradationLen + gradationNumberGap + textSize, mTextPaint);
            } else {//短刻度
                mPaint.setStrokeWidth(shortLineWidth);
                canvas.drawLine(distance, 0, distance, shortGradationLen, mPaint);
            }

            startNum += mNumberUnit;
            distance += gradationGap;
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        final int x = (int) event.getX();
        final int y = (int) event.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mDownX = x;
                isMoved = false;
                break;
            case MotionEvent.ACTION_MOVE:
                final int dx = x - mLastX;
                // 判断是否已经滑动
                if (!isMoved) {
                    final int dy = y - mLastY;
                    // 滑动的触发条件：水平滑动大于垂直滑动；滑动距离大于阈值
                    if (Math.abs(dx) < Math.abs(dy) || Math.abs(x - mDownX) < TOUCH_SLOP) {
                        break;
                    }
                    isMoved = true;
                }

                mCurrentDistance += -dx;
                if (mCurrentDistance <= 0) {
                    mCurrentDistance = 0;
                }
                if (mCurrentDistance >= mNumberRangeDistance - mWidthRangeNumber * gradationGap) {
                    mCurrentDistance = mNumberRangeDistance - mWidthRangeNumber * gradationGap;
                }
                calculateValue();
                break;
            case MotionEvent.ACTION_UP:
                invalidate();
                break;
        }
        mLastX = x;
        mLastY = y;
        return true;
    }

    private void calculateValue() {
        Log.i(TAG, "calculateValue: " + mCurrentDistance);
        invalidate();
    }
}
